﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using CARE.GraphProviderServiceReference;
using GraphLayout.Interface;
using prefuse.action.layout.graph;
using prefuse.action.layout;
using System.Threading;
using CARE;

namespace CARE
{
	public partial class GleeGraphDrawer : UserControl, ILayoutControler {
		//private String graphML;
		//private String model;
		private Graph m_graph;
		private Dictionary<String, Type> typeMap;
        GraphProviderServiceClient cl = new GraphProviderServiceClient();
		private Layout m_currentlayout;
		private bool layoutChanged = false;

		static SimulationVisualization simulationPage;

		#region ChangeHistory
		List<GraphElement> nodesAdded = new List<GraphElement>();
		List<GraphElement> nodesRemoved = new List<GraphElement>();
		List<GraphElement> nodesEdited = new List<GraphElement>();
		List<GraphLayout.GraphRepresentation.EdgeItem> edgesAdded = new List<GraphLayout.GraphRepresentation.EdgeItem>();
		List<GraphLayout.GraphRepresentation.EdgeItem> edgesRemoved = new List<GraphLayout.GraphRepresentation.EdgeItem>();
		#endregion

		double oldMouseX = 0.0;
		double oldMouseY = 0.0;
		bool mouseLeftButtonPressed = false;

		String token = "12";
		int m_simNumber = 0;
        int max_sim_steps = 0;
		private bool noZoomValueChanged = false;

		public int simNumber {
			get {
				return m_simNumber;
			}
			set {
				m_simNumber = value;
				lblSimulationNumber.Text = m_simNumber.ToString();
			}
		}
		private Boolean isContinous = false;

		public Layout currentlayout {
			get {
				return m_currentlayout;
			}
			set {
				m_currentlayout = value;
				m_currentlayout.Controller = this;
				String name = (from v in typeMap
							   where v.Value == m_currentlayout.GetType()
							   select v.Key).First();
				layoutChooser.SelectedItem = name;
			}
		}

        //public GleeGraphDrawer(String pgraphML, String pmodel, Point point, GraphProviderServiceSoapClient soapClient, Menu menu) {
        //    graphML = pgraphML;
        //    model = pmodel;
        //    InitializeComponent();
        //    cl = soapClient;
        //    m_menu = menu;
        //}

		public GleeGraphDrawer(SimulationVisualization simulationPage)
        {
            InitializeComponent();
			GleeGraphDrawer.simulationPage = simulationPage;
            this.Run.IsEnabled = false;
            this.nextStep.IsEnabled = false;
            this.SizeChanged += new SizeChangedEventHandler(GleeGraphDrawer_SizeChanged);            
            simulationPage.MouseLeftButtonDown += new MouseButtonEventHandler(simulationPage_MouseLeftButtonDown);
            simulationPage.MouseLeftButtonUp += new MouseButtonEventHandler(simulationPage_MouseLeftButtonUp);
            simulationPage.MouseLeave += new MouseEventHandler(simulationPage_MouseLeave);
            simulationPage.MouseMove += new MouseEventHandler(simulationPage_MouseMove);
        }

        void cl_getMaxSimTimeCompleted(Object sender, getSimulationMaxTimeCompletedEventArgs e)
        {
            max_sim_steps = e.Result;
            this.Run.IsEnabled = true;
            this.nextStep.IsEnabled = true;
        }

        void GleeGraphDrawer_SizeChanged(object sender, SizeChangedEventArgs e)
        {
            if (currentlayout != null)
            {
                //currentlayout.setLayoutAnchor(new Point(m_menu.ContentHost.ActualWidth / 2.0, m_menu.ContentHost.ActualHeight / 2.0));
                //currentlayout.Width = m_menu.ContentHost.ActualWidth;
                //currentlayout.Height = m_menu.ContentHost.ActualHeight;
				currentlayout.setLayoutAnchor(new Point(e.NewSize.Width / 2.0, e.NewSize.Height / 2.0));
				currentlayout.Width = e.NewSize.Width;
				currentlayout.Height = e.NewSize.Height;
            }
        }

        //public GleeGraphDrawer(Graph pgraphML, String pmodel, Point point, GraphProviderServiceSoapClient soapClient, Menu menu) {
        //    m_graph = pgraphML;
        //    model = pmodel;
        //    InitializeComponent();
        //    cl = soapClient;
        //    m_menu = menu;
        //}

		public void Page_Loaded(object o, EventArgs e) {
			// Required to initialize variables
			InitializeComponent();

			typeMap = Layout.ChildTypesNames(typeof(Layout));
			foreach (var item in typeMap)
				layoutChooser.Items.Add(item.Key);
			
			foreach (var item in simulationPage.GetAvailableStates()) {
				stateChooser.Items.Add(item);
				
				StackPanel child = new StackPanel() {
					Orientation = Orientation.Horizontal
				};
				Ellipse stateColor = new Ellipse() {
					Width = 10,
					Height = 10,
					Stroke = new SolidColorBrush(Color.FromArgb(255, 50, 50, 50)),
					StrokeThickness = 1.0,
					Fill = SimulationVisualization.GetColorForDisease(item)
				};
                TextBlock stateName = new TextBlock()
                {
					Text = item
				};
				
				child.Children.Add(stateColor);
				child.Children.Add(stateName);
				legend.Children.Add(child);
			}





			cl.GetAvailableMethodsOfCentralityCompleted += new EventHandler<GetAvailableMethodsOfCentralityCompletedEventArgs>(cl_GetAvailableMethodsOfCentralityCompleted);
			cl.GetAvailableMethodsOfCentralityAsync();
			cl.ComputeCentralityCompleted += new EventHandler<ComputeCentralityCompletedEventArgs>(cl_ComputeCentralityCompleted);

			try {
				SuspendLayout();
				//cl.CreateGraphCompleted += new EventHandler<CreateGraphCompletedEventArgs>(cl_CreateGraphCompleted);
                cl.StartSimulationCompleted += new EventHandler<StartSimulationCompletedEventArgs>(cl_StartSimulationCompleted);
				cl.NextStepCompleted += new EventHandler<NextStepCompletedEventArgs>(cl_NextStepCompleted);
				if (m_graph == null) {

                    var param = SimulationParameters.getInstance();

                    cl.StartSimulationAsync(new SimulationSetupSL() 
                    {
                        maxContactsPerStep = param.MaxContacts,
                        minContactsPerStep = param.MinContacts,
                        networkGraph = param.SocialNetworkGraph,
                        networkGraphML = param.SocialNetworkGraphML,
                        diseaseModelGraphML = param.DiseaseGraphML,
                        stateChangePlansSL = param.stateChangePlansSL,
                        stopConditionsSL = param.stopConditionsSL                        
                    }, "12");
					//cl.CreateGraphAsync(graphML, model, token, m_menu.setupSelector.MaxSteps);
				}
				else {
					cl_CreateGraphCompleted(null, new CreateGraphCompletedEventArgs(new object[] { m_graph }, null, false, null));
				}


				//cl.GetGraphAsync();
			}
			catch {
				//this.Details.Text = "Error while loading graph: " + graphResource + ". \n Loading a random graph instead.";
			}


		}

        void cl_StartSimulationCompleted(object sender, StartSimulationCompletedEventArgs e)
        {
			cl_CreateGraphCompleted(sender, new CreateGraphCompletedEventArgs(new object[]{e.Result}, e.Error, e.Cancelled, e.UserState));

            cl.getSimulationMaxTimeCompleted += new EventHandler<getSimulationMaxTimeCompletedEventArgs>(cl_getMaxSimTimeCompleted);
            cl.getSimulationMaxTimeAsync();
        }

		private void UpdateMap() {
			Dictionary<GraphElement, VisualItem> newMap = new Dictionary<GraphElement, VisualItem>();

			foreach (var item in simulationPage.map) {
				foreach (var newItem in m_graph.Vertices) {
					if (item.Key.ID == newItem.ID) {
						newMap.Add(newItem, item.Value);
					}
				}
			}

			simulationPage.map = newMap;
		}

		private void ComputeCentrality_Click(object sender, RoutedEventArgs e) {
			if (centralityChooser.SelectedItem != null) {
				SuspendLayout();
				cl.ComputeCentralityAsync(centralityChooser.SelectedItem.ToString(), m_graph);
			}
		}

		void cl_ComputeCentralityCompleted(object sender, ComputeCentralityCompletedEventArgs e) {
			m_graph = e.Result;

			UpdateMap();

			GraphElement max = m_graph.Vertices[0];
			double maxImportance = 0.0;
			foreach (var description in max.Keys)
				if (description.Key == "importance")
					maxImportance = double.Parse(description.Value);

			foreach (var v in m_graph.Vertices)
				foreach (var description in v.Keys)
					if (description.Key == "importance")
						if (double.Parse(description.Value) > maxImportance) {
							max = v;
							maxImportance = double.Parse(description.Value);
						}

			if (currentlayout is TreeLayout) {
				((TreeLayout)currentlayout).setLayoutRoot((GraphLayout.GraphRepresentation.NodeItem)simulationPage.map[max]);
				((TreeLayout)currentlayout).CreateTree(((TreeLayout)currentlayout).getLayoutRoot());

				currentlayout.setLayoutAnchor(new Point(((TreeLayout)currentlayout).getLayoutRoot().X,
						((TreeLayout)currentlayout).getLayoutRoot().Y));
			}
			
			ResumeLayout();
		}
        
		void cl_GetAvailableMethodsOfCentralityCompleted(object sender, GetAvailableMethodsOfCentralityCompletedEventArgs e) {
			foreach (var item in e.Result)
				centralityChooser.Items.Add(item);
		}

		void cl_CreateGraphCompleted(object sender, CreateGraphCompletedEventArgs e) {
			Graph g = e.Result;
			m_graph = e.Result;

			GraphLayout.GraphRepresentation.Graph gg = new GraphLayout.GraphRepresentation.Graph();
			gg.Nodes = new System.Collections.ObjectModel.ObservableCollection<VisualItem>();
			gg.Edges = new System.Collections.ObjectModel.ObservableCollection<GraphLayout.GraphRepresentation.EdgeItem>();

            currentlayout = new RadialTreeLayout("", gg, 100);
            currentlayout.setLayoutAnchor(new Point(MainCanvas.ActualWidth / 2.0, MainCanvas.ActualHeight / 2.0));
            currentlayout.Width = this.ActualWidth;
            currentlayout.Height = this.ActualHeight;

			simulationPage.map.Clear();

			foreach (var item in g.Vertices) {
				GraphElement elem = item;
                var node = CreateNodeCanvas(elem, simulationPage);
                node.NodeSelected += new MouseEventHandler(nodeCanvas_NodeSelected);
				gg.Nodes.Add(node);                
				((GraphLayout.GraphRepresentation.NodeItem)gg.Nodes.Last()).Graph = gg;
				((GraphLayout.GraphRepresentation.NodeItem)gg.Nodes.Last()).X = (float)currentlayout.getLayoutAnchor().X;
				((GraphLayout.GraphRepresentation.NodeItem)gg.Nodes.Last()).Y = (float)currentlayout.getLayoutAnchor().Y;
				gg.Nodes.Last().Element = item;
				simulationPage.map.Add(item, gg.Nodes.Last());

				((GraphLayout.GraphRepresentation.NodeItem)gg.Nodes.Last()).MouseEnter += new MouseEventHandler(SetInfoPanel);
				((GraphLayout.GraphRepresentation.NodeItem)gg.Nodes.Last()).MouseLeave += new MouseEventHandler(ResetInfoPanel);

				currentlayout.Children.Add((GraphLayout.GraphRepresentation.NodeItem)gg.Nodes.Last());
			}

			//DebugGraph(gg);//test
			foreach (var item in g.Edges) {
				var n1 = (from v in g.Vertices
						  where v.ID == item.Source
						  select v).First();
				var n2 = (from v in g.Vertices
						  where v.ID == item.Target
						  select v).First();

				GraphLayout.GraphRepresentation.EdgeItem e1 = new GraphLayout.GraphRepresentation.EdgeItem();
				e1.Target = simulationPage.map[n2];
				e1.Source = simulationPage.map[n1];
				e1.Graph = gg;

				gg.Edges.Add(e1);
			}

			try {
				currentlayout.Init();
				currentlayout.DrawLayout(100);
			}
			catch (Exception ex) {
				MainCanvas.Children.Add(new TextBlock() {
					Text = ex.Message
				});
			};
            currentlayout.SetValue(Grid.ColumnProperty, 1);
            currentlayout.SetValue(Canvas.ZIndexProperty, -10);
			this.MainCanvas.Children.Add(currentlayout);
		}

		public static GraphLayout.GraphRepresentation.NodeItem CreateNodeCanvas(GraphElement n, SimulationVisualization simulationPage) {
			Color projColor = Color.FromArgb(128, 100, 55, 55);
			
			Brush textColor = new SolidColorBrush(Colors.Black);
			//Brush borderColor = new SolidColorBrush(Color.FromArgb(255, 255, 100, 100));
			Brush borderColor = new SolidColorBrush(Color.FromArgb(255, 50, 50, 50));

			//TODO: add lebel
            String text = String.Empty;
            foreach (var description in n.Keys)
            {
                if (description.Key == "stateName")
                {
                    text = description.Value;
                    break;
                }
            }

            Brush projBrush = SimulationVisualization.GetColorForDisease(text);

			/*TextBlock title = new TextBlock() {
				Foreground = textColor,
				Text = text,
				FontSize = 12
			};*/

			double Height = 25d;
			double Width = 25d;
			//double Width = (title.ActualWidth + 4) < Height ? Height : title.ActualWidth + 4;

			GraphLayout.GraphRepresentation.NodeItem nodeCanvas = new GraphLayout.GraphRepresentation.NodeItem() {
				Width = Width,
				Height = Height
			};

			//nodeCanvas.Title = title;

			Ellipse nodeBkg = new Ellipse() {
				//Width = Width,
				//Height = Height,
				Width = 25d,
				Height = 25d,
				Fill = projBrush,
				Stroke = borderColor
			};


			//nodeBkg.RadiusX = 10;
			//nodeBkg.RadiusY = 10;

			nodeCanvas.Children.Add(nodeBkg);
            
			//nodeCanvas.Children.Add(title);

			#region Center the title

			//double left = (nodeBkg.Width - title.ActualWidth) / 2;
			//double top = (nodeBkg.Height - title.ActualHeight) / 2;
			//title.SetValue(Canvas.LeftProperty, left);
			//title.SetValue(Canvas.TopProperty, top);

			#endregion

			return nodeCanvas;
		}

        void nodeCanvas_NodeSelected(object sender, MouseEventArgs e)
        {
            var curr = sender as GraphLayout.GraphRepresentation.NodeItem;
            var prev = curr.Graph.PreviousSelectedNode as GraphLayout.GraphRepresentation.NodeItem;
			
            if (prev != null)
            {
                GraphElement n = prev.Element as GraphElement;

                String text = String.Empty;
                foreach (var description in n.Keys)
                {
                    if (description.Key == "stateName")
                    {
                        text = description.Value;
                        break;
                    }
                }

                ((Ellipse)prev.Children[0]).Fill = SimulationVisualization.GetColorForDisease(text);
                ((Ellipse)prev.Children[0]).Stroke = new SolidColorBrush(Color.FromArgb(255, 50, 50, 50));
                ((Ellipse)prev.Children[0]).StrokeThickness = 1.0;
            }
            if (curr != null)
            {
                GraphElement n = curr.Element as GraphElement;

                details.UpdateDetails(n.Keys);
                String text = String.Empty;

                foreach (var description in n.Keys)
                {
                    if (description.Key == "stateName")
                    {
                        text = description.Value;
                    }
                }


                int i = 0;
                for (; i < stateChooser.Items.Count; i++)
                {
                    if (stateChooser.Items[i].ToString() == text)
                        break;
                }
                
                ((Ellipse)curr.Children[0]).Fill = new SolidColorBrush(Color.FromArgb(128, 55, 55, 100));
                ((Ellipse)curr.Children[0]).Stroke = new SolidColorBrush(Color.FromArgb(255, 0, 0, 0));
                ((Ellipse)curr.Children[0]).StrokeThickness = 2.0;
                if(stateChooser.Items.Count != 0)
                    stateChooser.SelectedIndex = i;
            }
        }

		private void simulationPage_MouseLeftButtonDown(object sender, MouseButtonEventArgs e) {
			(sender as SimulationVisualization).CaptureMouse();
			mouseLeftButtonPressed = true;
			oldMouseX = e.GetPosition(null).X;
			oldMouseY = e.GetPosition(null).Y;
			(sender as SimulationVisualization).Cursor = Cursors.Hand;
		}

		private void simulationPage_MouseLeftButtonUp(object sender, MouseButtonEventArgs e) {
			(sender as SimulationVisualization).ReleaseMouseCapture();
			mouseLeftButtonPressed = false;
			(sender as SimulationVisualization).Cursor = Cursors.Arrow;
		}

		private void simulationPage_MouseLeave(object sender, MouseEventArgs e) {
			mouseLeftButtonPressed = false;
		}

		private void simulationPage_MouseMove(object sender, MouseEventArgs e) {
			if (mouseLeftButtonPressed == true && currentlayout.IsMouseCaptured == false)
				foreach (var node in currentlayout.Graph.Nodes) {
					node.X += (float)(e.GetPosition(null).X - oldMouseX);
					node.Y += (float)(e.GetPosition(null).Y - oldMouseY);
				}
			oldMouseX = e.GetPosition(null).X;
			oldMouseY = e.GetPosition(null).Y;
		}

		/*private void ContentHostParent_KeyDown(object sender, KeyEventArgs e) {
			if (e.Key != Key.A
			 && e.Key != Key.D
			 && e.Key != Key.W
			 && e.Key != Key.S)
				return;
			
			foreach (var node in currentlayout.Graph.Nodes)
				if (e.Key == Key.A)
					node.X -= 5;
				else if (e.Key == Key.D)
					node.X += 5;
				else if (e.Key == Key.W)
					node.Y -= 5;
				else node.Y += 5;
		}*/

		private void SelectNode(GraphLayout.GraphRepresentation.NodeItem node) {
			node.Select();
		}

		private void Remove_Click(object sender, RoutedEventArgs e) {
			if (((GraphLayout.GraphRepresentation.Graph)currentlayout.Graph).SelectedNode == null)
				return;

			GraphLayout.GraphRepresentation.NodeItem node = (GraphLayout.GraphRepresentation.NodeItem)
				((GraphLayout.GraphRepresentation.Graph)currentlayout.Graph).SelectedNode;
			((GraphLayout.GraphRepresentation.Graph)currentlayout.Graph).SelectedNode = null;

            cl.removeNodeAsync(token, ((GraphElement)node.Element).ID);

			List<GraphLayout.GraphRepresentation.EdgeItem> edgesToRemove = new List<GraphLayout.GraphRepresentation.EdgeItem>();
			foreach (var edge in currentlayout.Graph.Edges)
				if (edge.Source == node || edge.Target == node) {
					edgesToRemove.Add(edge);
					edgesRemoved.Add(edge);
				}

			foreach (var edge in edgesToRemove)
				currentlayout.Graph.Edges.Remove(edge);

			var graphNode = (from v in simulationPage.map
							 where v.Value == node
							 select v.Key).First();
			nodesRemoved.Add(graphNode);
			
			if (node == ((GraphLayout.GraphRepresentation.Graph)currentlayout.Graph).SelectedNode)
				((GraphLayout.GraphRepresentation.Graph)currentlayout.Graph).SelectedNode = null;
			if (node == ((GraphLayout.GraphRepresentation.Graph)currentlayout.Graph).PreviousSelectedNode)
				((GraphLayout.GraphRepresentation.Graph)currentlayout.Graph).PreviousSelectedNode = null;
			if (currentlayout is TreeLayout)
				if (((TreeLayout)currentlayout).getLayoutRoot() == node)
					((TreeLayout)currentlayout).setLayoutRoot(null);
			currentlayout.Graph.Nodes.Remove(node);
		}

		private void Add_Click(object sender, RoutedEventArgs e) {
			//nodesAdded.Add();
			//edgesAdded.Add();
		}

		private void StateChooser_SelectionChanged(object sender, SelectionChangedEventArgs e) {
			ChangeNodeState((GraphLayout.GraphRepresentation.NodeItem)
				((GraphLayout.GraphRepresentation.Graph)currentlayout.Graph).SelectedNode);
		}

		private void ChangeNodeState(GraphLayout.GraphRepresentation.NodeItem node) {
			var graphNode = (from v in simulationPage.map
							 where v.Value == node
							 select v.Key).First();

			foreach (var item in graphNode.Keys)
				if (item.Key == "stateName") {
					item.Value = stateChooser.SelectedItem.ToString();

                    cl.changeNodeStateAsync(token, graphNode.ID, item.Value);

					//node.Title.Text = stateChooser.SelectedItem.ToString();
				}

			nodesEdited.Add(graphNode);
		}

		public static void SetInfoPanel(object sender, MouseEventArgs e) {            
			GraphLayout.GraphRepresentation.NodeItem node = sender as GraphLayout.GraphRepresentation.NodeItem;

			if (node.FindName(node.GetHashCode() + "Info") != null)
				return;

			Canvas info = new Canvas() {
				Name = node.GetHashCode() + "Info"
			};

			string keys = "";
			var graphNode = (from v in simulationPage.map
							 where v.Value == node
							 select v.Key).First();
			foreach (var key in graphNode.Keys)
				keys += "  " + key.Key + " = " + key.Value + "  \n";
			keys = keys.Substring(0, keys.Length - 1);
			TextBlock t = new TextBlock() {
				Text = keys,
				FontSize = 12.0
			};

			Canvas border = new Canvas();

            Rectangle p = new Rectangle();            
            p.Width = t.ActualWidth;
            p.Height = t.ActualHeight;
            p.Opacity = 0.8;
			p.Fill = new SolidColorBrush(Colors.White);
			p.Stroke = new SolidColorBrush(Colors.Blue);
            p.SetValue(Canvas.TopProperty, 0.0);
            p.SetValue(Canvas.LeftProperty, 0.0);
            p.RadiusX = 10;
            p.RadiusY = 10;

            Polygon tri = new Polygon();
            tri.Points = new PointCollection
            {
                new Point(node.Bounds.X + 50 + 33, node.Bounds.Y + (p.Height)),
                new Point(node.Bounds.X + 80 + 33, node.Bounds.Y + (p.Height)),
                new Point(node.Bounds.X + 33, node.Bounds.Y + (p.Height + 10 + 5))
            };
            tri.Fill = new SolidColorBrush(Colors.Blue);
            tri.Stroke = new SolidColorBrush(Colors.Blue);
            border.Children.Add(p);
            info.Children.Add(tri);

			Canvas.SetLeft(info, node.Bounds.X + node.Width - 30);
            Canvas.SetTop(info, node.Bounds.Y - (p.Height +10));
			
			info.Children.Add(border);
			info.Children.Add(t);
			
			Canvas.SetZIndex(node, (int)node.GetValue(Canvas.ZIndexProperty) + 1);
			node.Children.Add(info);
		}

        public static void ResetInfoPanel(object sender, MouseEventArgs e)
        {
			GraphLayout.GraphRepresentation.NodeItem node = sender as GraphLayout.GraphRepresentation.NodeItem;

			Canvas c = null;
			foreach (var child in node.Children)
				if (child is Canvas)
					if (((Canvas)child).Name == (node.GetHashCode() + "Info")) {
						c = (Canvas)child;
						break;
					}

			Canvas.SetZIndex(node, (int)node.GetValue(Canvas.ZIndexProperty) - 1);
			node.Children.Remove(c);
		}

		private void LayoutChooser_SelectionChanged(object sender, SelectionChangedEventArgs e) {
			layoutChanged = true;
		}

		private void BalanceGraph_Click(object sender, RoutedEventArgs e) {
			Point anchor = currentlayout.getLayoutAnchor();

			noZoomValueChanged = true;
			zoom.Value = 5;

			if (layoutChanged == true) {
				layoutChanged = false;

				GraphLayout.GraphRepresentation.Graph g = (GraphLayout.GraphRepresentation.Graph)currentlayout.Graph;
				GraphLayout.GraphRepresentation.Graph graph = new GraphLayout.GraphRepresentation.Graph();
				graph.Nodes = new System.Collections.ObjectModel.ObservableCollection<VisualItem>();
				graph.Edges = new System.Collections.ObjectModel.ObservableCollection<GraphLayout.GraphRepresentation.EdgeItem>();

				GraphLayout.GraphRepresentation.NodeItem root = null;
				if (currentlayout is TreeLayout)
					root = currentlayout.getLayoutRoot();

				var type = typeMap[layoutChooser.SelectedItem.ToString()];
				//currentlayout.Children.Clear();
				MainCanvas.Children.Remove(currentlayout);
				currentlayout = (Layout)Activator.CreateInstance(type, new object[] { graph });

				Dictionary<VisualItem, VisualItem> mapGGraph = new Dictionary<VisualItem, VisualItem>();
				foreach (var item in g.Nodes) {
					GraphLayout.GraphRepresentation.NodeItem node = (GraphLayout.GraphRepresentation.NodeItem)item;
					UIElement nodeBkg = node.Children[0];
					//UIElement title = node.Children[1];
					node.Children.Clear();
					GraphLayout.GraphRepresentation.NodeItem nodeCanvas = new GraphLayout.GraphRepresentation.NodeItem() {
						Width = node.Width,
						Height = node.Height,
						//Title = node.Title
					};
                    nodeCanvas.NodeSelected +=new MouseEventHandler(nodeCanvas_NodeSelected);
					nodeCanvas.Children.Add(nodeBkg);
					//nodeCanvas.Children.Add(title);
					graph.Nodes.Add(nodeCanvas);
					((GraphLayout.GraphRepresentation.NodeItem)graph.Nodes.Last()).Graph = graph;
					((GraphLayout.GraphRepresentation.NodeItem)graph.Nodes.Last()).X = node.X;
					((GraphLayout.GraphRepresentation.NodeItem)graph.Nodes.Last()).Y = node.Y;
					graph.Nodes.Last().Element = node.Element;
					mapGGraph.Add(node, graph.Nodes.Last());

					((GraphLayout.GraphRepresentation.NodeItem)graph.Nodes.Last()).MouseEnter += new MouseEventHandler(SetInfoPanel);
					((GraphLayout.GraphRepresentation.NodeItem)graph.Nodes.Last()).MouseLeave += new MouseEventHandler(ResetInfoPanel);

					currentlayout.Children.Add((GraphLayout.GraphRepresentation.NodeItem)graph.Nodes.Last());
				}
				foreach (var edge in g.Edges) {
					var n1 = (from n in g.Nodes
							  where n == edge.Source
							  select n).First();
					var n2 = (from n in g.Nodes
							  where n == edge.Target
							  select n).First();

					GraphLayout.GraphRepresentation.EdgeItem e1 = new GraphLayout.GraphRepresentation.EdgeItem();
					e1.Source = mapGGraph[n1];
					e1.Target = mapGGraph[n2];
					e1.Graph = graph;

					graph.Edges.Add(e1);
				}

				Dictionary<GraphElement, VisualItem> newMap = new Dictionary<GraphElement, VisualItem>();
				GraphLayout.Interface.VisualItem vi = null;
				foreach (var item in simulationPage.map)
					if (mapGGraph.TryGetValue(item.Value, out vi) == true)
						newMap.Add(item.Key, mapGGraph[item.Value]);
				simulationPage.map = newMap;

				if (root != null && currentlayout is TreeLayout)
					((TreeLayout)currentlayout).setLayoutRoot((GraphLayout.GraphRepresentation.NodeItem)mapGGraph[root]);

				if (g.PreviousSelectedNode != null)
					graph.PreviousSelectedNode = mapGGraph[g.PreviousSelectedNode];
				if (g.SelectedNode != null) {
					graph.SelectedNode = mapGGraph[g.SelectedNode];
					SelectNode((GraphLayout.GraphRepresentation.NodeItem)mapGGraph[g.SelectedNode]);
				}

				//currentlayout.Width = m_menu.ContentHost.Width;
				//currentlayout.Height = m_menu.ContentHost.Height;
				currentlayout.Width = this.Width;
				currentlayout.Height = this.Height;
				currentlayout.SetValue(Canvas.TopProperty, 1.0);
				currentlayout.SetValue(Canvas.LeftProperty, 1.0);
				MainCanvas.Children.Insert(0, currentlayout);
			}

			currentlayout.setLayoutAnchor(anchor);

			currentlayout.Init();
			currentlayout.DrawLayout(100);
		}

		private void SetAsRoot_Click(object sender, RoutedEventArgs e) {
			if (currentlayout is TreeLayout) {
				((TreeLayout)currentlayout).setLayoutRoot((GraphLayout.GraphRepresentation.NodeItem)
						((GraphLayout.GraphRepresentation.Graph)currentlayout.Graph).SelectedNode);
				((TreeLayout)currentlayout).CreateTree(((TreeLayout)currentlayout).getLayoutRoot());

				currentlayout.setLayoutAnchor(new Point(((TreeLayout)currentlayout).getLayoutRoot().X,
						((TreeLayout)currentlayout).getLayoutRoot().Y));

                BalanceGraph_Click(sender, e);
			}
		}

		#region ILayoutControler Members

		public void SuspendLayout() {
			foreach (var item in ControlPanel.Children) {
				if (item is Button) {
					Button b = item as Button;
					b.IsEnabled = false;
				}
				else
					if (item is Slider) {
						Slider s = item as Slider;
						s.IsEnabled = false;
					}
			}

            //m_menu.LeftPanel.Visibility = Visibility.Collapsed;
		}

		public void ResumeLayout() {
			foreach (var item in ControlPanel.Children) {
				if (item is Button) {
					Button b = item as Button;
					b.IsEnabled = true;
				}
				else
					if (item is Slider) {
						Slider s = item as Slider;
						s.IsEnabled = true;
					}
			}
            //m_menu.LeftPanel.Visibility = Visibility.Visible;
		}

		#endregion

		private void cl_NextStepCompleted(object sender, NextStepCompletedEventArgs e) {
			foreach (var item in simulationPage.map)
            {
				foreach (var element in e.Result.Vertices) {
					if (item.Key.ID == element.ID) {
                        var node = (GraphLayout.GraphRepresentation.NodeItem)item.Value;
                        foreach (var description in element.Keys)
                        {
                            if (description.Key == "stateName")
                            {
                                ((Ellipse)node.Children[0]).Fill = SimulationVisualization.GetColorForDisease(description.Value);
                                break;
                            }
                        }
                        

						item.Key.Keys = element.Keys;
						item.Key.Height = element.Height;
						item.Key.Width = element.Width;
						item.Key.x = element.x;
						item.Key.y = element.y;
						break;
					}
				}
			}


            simNumber++;
            if (simNumber >= max_sim_steps)
            {
                isContinous = false;
                this.Run.IsEnabled = false;
                return;

            }

			if (isContinous) {
				cl.NextStepAsync(token);
			}
			else {
				this.nextStep.IsEnabled = true;
			}
           
			//this.SimulationNumber.Text = simNumber.ToString();
		}

		private void NextStep_Click(object sender, RoutedEventArgs e) {
			this.nextStep.IsEnabled = false;
			cl.NextStepAsync(token);
		}

		private void Run_Click(object sender, RoutedEventArgs e) {
			simulationPage.EnableNext();
			
			if (!isContinous) {
				this.Run.Content = "Stop";
				isContinous = true;
				this.nextStep.IsEnabled = false;
				cl.NextStepAsync(token);
			}
			else {
				this.Run.Content = "Run";
				isContinous = false;
				this.nextStep.IsEnabled = true;
			}
		}

		private void Zoom_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e) {
			if (currentlayout == null || noZoomValueChanged == true) {
				noZoomValueChanged = false;
				return;
			}

			double centralX = MainCanvas.ActualWidth / 2;
			double centralY = MainCanvas.ActualHeight / 2;
			//double centralX = currentlayout.Width / 2;
			//double centralY = currentlayout.Height / 2;
			double scale = (e.NewValue + 1) / (e.OldValue + 1);
			foreach (var node in currentlayout.Graph.Nodes) {
				double relX = node.X - centralX;
				double relY = node.Y - centralY;

				node.X = (float)(scale * relX + centralX);
				node.Y = (float)(scale * relY + centralY);
			}
		}
	}
}
